﻿#region << 版 本 注 释 >>
/*----------------------------------------------------------------
 * 版权所有 (c) 2022 北京超维景生物科技有限公司 保留所有权利。
 * CLR版本：4.0.30319.42000
 * 文件名：Kernel
 * 
 * 创建者：huangyang
 * 电子邮箱：huangyang@tvscope.cn
 * 创建时间：2023/2/8 16:01:41
 * 版本：V1.0.0
 * 描述：
 *
 * ----------------------------------------------------------------
 * 修改人：
 * 时间：
 * 修改说明：
 *
 * 版本：V1.0.1
 *----------------------------------------------------------------*/
#endregion << 版 本 注 释 >>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ImageK.Exceptions;
using ImageK.Java;

namespace ImageK.IO
{
    /// <summary>
    /// This class uses a memory cache to allow seeking within
    /// an InputStream.Based on the JAI MemoryCacheSeekableStream class.
    /// Can also be constructed from a RandomAccessFile, which uses less
    /// memory since the memory cache is not required.
    /// </summary>
    public class RandomAccessStream: InputStream
    {
        private static int BLOCK_SIZE = 1024;
        private static int BLOCK_MASK = 1023;
        private static int BLOCK_SHIFT = 10;

        public FileStream _src;
        private RandomAccessFile _ras = null;

        private long _pointer;
        private List<byte> data;
        private long _length;
        private bool _foundEos;

        public RandomAccessStream(FileStream fs)
        {
            _pointer = 0L;
            data = new List<byte>();
            _length = 0L;
            _foundEos = false;
            _src = fs;
        }

        public RandomAccessStream(RandomAccessStream fs)
        {
            _pointer = 0L;
            data = new List<byte>();
            _length = 0L;
            _foundEos = false;
            _src = fs._src;
        }

        public long getLongFilePointer()
        {
            return _src.Position;

            //todo:
            // if (_ras!=null)
            //     return _ras.getFilePointer();
            // else
            //     return _pointer;
        }

        public long skip(long skipCount)
        {
            var currentPosition = _src.Position;
            var newPosition = _src.Seek(skipCount, SeekOrigin.Current);
            return newPosition - currentPosition;
        }

        public int Read()
        {
            try
            {
                //todo:
                return _src.ReadByte();


                // if (_ras != null)
                //     return _br.ReadByte();
                // long l = _pointer + 1L;
                // long l1 = ReadUntil(l);
                // if (l1 >= l)
                // {
                //     byte[] abyte0 = data.GetRange((int)(_pointer >> BLOCK_SHIFT), BLOCK_SIZE).ToArray();
                //     return abyte0[(int)(_pointer++ & BLOCK_MASK)] & 0xff;
                // }
                // else
                //     return -1;
            }
            catch
            {
                throw new IOException();
            }
        }

        public void ReadFully(byte[] bytes)
        {
            ReadFully(bytes, bytes.Length);
        }

        public void ReadFully(byte[] bytes, int len)
        {
            int read = 0;
            do
            {
                int l = Read(bytes, read, len - read);
                if (l < 0) break;
                read += l;
            } while (read < len);
        }

        private long ReadUntil(long l)
        {
            try
            {
                if (l < _length)
                    return l;
                if (_foundEos)
                    return _length;
                int i = (int)(l >> BLOCK_SHIFT);
                int j = (int)(_length >> BLOCK_SHIFT);
                for (int k = j; k <= i; k++)
                {
                    byte[] abyte0 = new byte[BLOCK_SIZE];
                    // data.AddRange(abyte0);
                    int i1 = BLOCK_SIZE;
                    int j1 = 0;
                    while (i1 > 0)
                    {
                        int k1 = _src.Read(abyte0, j1, i1);
                        if (k1 == -1)
                        {
                            data.AddRange(abyte0);
                            _foundEos = true;
                            return _length;
                        }
                        j1 += k1;
                        i1 -= k1;
                        _length += k1;
                    }
                    data.AddRange(abyte0);
                }
                return _length;
            }
            catch
            {
                throw new IOException();
            }
        }


        public void Seek(long loc)
        {
            _src.Seek(loc, SeekOrigin.Begin);

            //IJ.log("seek (long): "+loc+"  "+(ras!=null));
            // if (_ras != null)
            // {
            //     _ras.seek(loc); 
            //     return;
            // }
            // if (loc < 0L)
            //     _pointer = 0L;
            // else
            //     _pointer = loc;
        }

        public int ReadInt()
        {
            int i = Read();
            int j = Read();
            int k = Read();
            int l = Read();
            if ((i | j | k | l) < 0)
                throw new EOFException();
            else
                return (i << 24) + (j << 16) + (k << 8) + l;
        }

        public long ReadLong()
        {
            return ((long)ReadInt() << 32) + ((long)ReadInt() & 0xffffffffL);
        }

        public double ReadDouble()
        {
            return BitConverter.Int64BitsToDouble(ReadLong());
        }

        public short ReadShort() 
        {
            try
            {
                int i = Read();
                int j = Read();
                if ((i | j) < 0)
                    throw new EOFException();
                else
                    return (short)((i << 8) + j);
            }
            catch
            {
                throw new IOException();
            }
        }

        public float ReadFloat()
        {
            return BitConverter.Int32BitsToSingle(ReadInt());
        }

        public int Read(byte[] bytes, int off, int len)
        {
            if (bytes == null)
                throw new NullReferenceException();

            //todo:
            return _src.Read(bytes, off, len);

            // if (_ras != null)
            //     return _ras.read(bytes, off, len);
            // if (off < 0 || len < 0 || off + len > bytes.Length)
            //     throw new IndexOutOfRangeException();
            // if (len == 0)
            //     return 0;
            // long l = ReadUntil(_pointer + len);
            // if (l <= _pointer)
            //     return -1;
            // else
            // {
            //     byte[] abyte1 = data.GetRange((int)(_pointer >> BLOCK_SHIFT), BLOCK_SIZE).ToArray();
            //     int k = Math.Min(len, BLOCK_SIZE - (int)(_pointer & BLOCK_MASK));
            //     Array.Copy(abyte1, (int)(_pointer & BLOCK_MASK), bytes, off, k);
            //     _pointer += k;
            //     return k;
            // }
        }




        public void Close() 
        {
            try
            {
                //ij.IJ.log("close: "+(data!=null?""+data.size():""));
                if (_ras != null)
                    _ras.Close();
                else
                {
                    data.Clear();
                    _src.Close();
                }
            }
            catch
            {
                throw new IOException();
            }
        }
    }
}
